﻿(function () {
    var formattag = CKEDITOR.plugins.formattag = {
        name: 'formattag',
        brClassName: 'plugin_',
        spaceClassName: 'plugin_',
        _innerHTML: '',
        console: window.console || { log: function () { window.console && window.console.log && window.console.log(arguments[0]); } },
        instances: {},
        enable: false,
        repeat: false,
        getDisplayNode: function (editor) {
            var flag = new CKEDITOR.dom.element('span', editor.document);
            flag.setHtml("&nbsp;");
            flag.data('cke-editable', 1);
            flag.setAttribute('contentEditable', 'false');
            flag.disableContextMenu();
            flag.unselectable();
            return flag;
        },
        getBrNode: function (editor) {
            var node = formattag.getDisplayNode(editor);
            node.data(formattag.name, 'br');
            node.addClass(formattag.brClassName);
            return node;
        },
        getSpaceNode: function (editor) {
            var node = formattag.getDisplayNode(editor);
            node.data(formattag.name, 'space');
            node.addClass(formattag.spaceClassName);
            return node;
        },
        isBrNode: function (element) {
            return element && element.type == 1 && element.data(formattag.name) == "br";
        },
        isSpaceNode: function (element) {
            return element && element.type == 1 && element.data(formattag.name) == "space";
        },
        getTextNodes: function (node) {
            var textNodes = [];
            if (node.type == 3) {
                textNodes.push(node);
            } else {
                var children = node.getChildren();
                for (var i = 0; i < children.count() ; i++) {
                    var child = this.getTextNodes(children.getItem(i));
                    textNodes = textNodes.concat(child);
                }
            }
            return textNodes;
        },
        clearFormatTag: function (content) {
            /// <summary>检查并清除html中的回车符</summary>
            try {
                content = window.external.ClearControlChr(content);
            } catch (e) {
                //console.log("清除回车符和空格标记失败" + e.toString());
                var spaceReg = new RegExp("<span[^>]*class=\\\"?plugin_formattag_space\\\"?[^>]*>.*?</span>", "ig");
                var brReg = new RegExp("<span[^>]*class=\\\"?plugin_formattag_br\\\"?[^>]*>.*?</span>", "ig");
                content = content.replace(spaceReg, "&nbsp;");
                content = content.replace(brReg, "");
            }
            return content;
        },
        setFormatTag: function (content) {
            try {
                content = window.external.SetControlChr(content, true);
            } catch (e) {
                //console.log("高亮回车符和空格标记失败" + e.toString());
                var spaceReg = new RegExp("(&#160;|&nbsp;)", "ig");
                var brReg = new RegExp("(<br[^>]*>)", "ig");
                content = content.replace(spaceReg, "<span class=\"plugin_formattag_space\" data-formattag=\"space\">$1</span>");
                content = content.replace(brReg, "<span class=\"plugin_formattag_br\" data-formattag=\"br\" contentEditable=false  data-cke-editable=\"1\">&nbsp;</span>$1");
            }
            return content;
        },
        setSpaceTag: function (content) {

        },
        reset: function (editor) {
            /// <summary>重新设置回车符状态</summary>
            if (!this.enable) {
                return;
            }
            var container;
            if (editor.elementMode == CKEDITOR.ELEMENT_MODE_INLINE) {
                container = editor.container;
            } else {
                container = editor.document.getBody();
            }
            formattag._innerHTML = container.getHtml();
            var html = formattag.clearFormatTag(formattag._innerHTML);
            html = formattag.setFormatTag(html);
            if (formattag._innerHTML != html) {
                container.setHtml(formattag._innerHTML);
            }
        },
        fixFlag: function (range) {
            /// <summary>当删除内容的时候修正回车符号</summary>
            var selNode = range.startContainer;
            var flag = null, before = null;
            if (formattag.isBrNode(selNode)) {
                flag = selNode;
            } else {
                if (selNode && selNode.type == CKEDITOR.NODE_TEXT) {
                    //选择文本节点需要先判断父节点，然后找出前一个节点
                    var parent = selNode.getParent();
                    if (formattag.isBrNode(parent)) {
                        //如果插入的内容在特殊标记里面，需要修正内容，并修正光标
                        selNode.insertBefore(parent);
                        range.setStartAfter(selNode);
                        range.collapse(true);
                        range.select();
                        return;
                    } else {
                        before = selNode.getPrevious();
                        while (before && before.type != CKEDITOR.NODE_ELEMENT) {
                            before = before.hasPrevious() && before.getPrevious();
                        }
                    }
                } else if (selNode.type == CKEDITOR.NODE_ELEMENT
                            && !range.checkStartOfBlock()
                            && !range.checkEndOfBlock()) {
                    //非文本节点，需要找出当前选中的节点
                    before = selNode.getChild(range.startOffset - 1);
                }

                if (formattag.isBrNode(before)) {
                    flag = before;
                }
            }
            if (flag) {
                formattag.console.log("插入内容后修正光标");
                range.setStartBefore(flag);
                range.collapse(true);
                range.select();
            }
        }
    };
    formattag.brClassName += formattag.name + '_br';
    formattag.spaceClassName += formattag.name + '_space';
    //debugger;
    //CKEDITOR.tools.extend(CKEDITOR.plugins.formattag, plugin);
    //console.log(CKEDITOR.plugins.formattag);
    CKEDITOR.plugins.add(formattag.name, {
        //requires: ['tabletools'],
        init: function (editor) {
            // 当文本粘帖到编辑器中，删除 span[data-scaytid]
            var dataFilter = editor.dataProcessor && editor.dataProcessor.dataFilter;
            dataFilter && dataFilter.addRules({
                elements: {
                    span: function (element) {
                        var attrs = element.attributes;
                        if (element.attributes['data-' + formattag.name]) {
                            delete element.name;
                        }
                    }
                }
            });
            //添加工具栏按钮
            var pluginCmd = editor.addCommand(formattag.name, {
                canUndo: false,
                exec: function (editor) {
                    //debugger;
                    this.toggleState();
                    formattag.enable = this.state == CKEDITOR.TRISTATE_ON;
                    var sel = editor.getSelection();
                    var bookmarks = sel && sel.createBookmarks(true);

                    var container;
                    if (editor.elementMode == CKEDITOR.ELEMENT_MODE_INLINE) {
                        container = editor.container;
                    } else {
                        container = editor.document.getBody();
                    }
                    formattag._innerHTML = container.getHtml();
                    var html;
                    if (formattag.enable === true) {
                        html = formattag.setFormatTag(formattag._innerHTML);
                    } else {
                        html = formattag.clearFormatTag(formattag._innerHTML);
                    }
                    if (html != formattag._innerHTML) {
                        formattag._innerHTML = html;
                        container.setHtml(formattag._innerHTML);
                    }
                    if (bookmarks) {
                        try {
                            sel.selectBookmarks(bookmarks);
                        } catch (e) {

                        }
                    }
                }
            });
            editor.ui.addButton('FormatTag', {
                label: '显示格式标记',
                icon: this.path + formattag.name + '.png',
                command: formattag.name
            });

            editor.on("key", function (evt) {
                /// <summary>keydown时的操作</summary>
                return;
                if (formattag.enable && evt.data.keyCode == 13 || evt.data.keyCode == CKEDITOR.SHIFT + 13) {
                    var flag = formattag.getBrNode(editor);
                    evt.editor.insertElement(flag);
                }
            });

            editor.on("mode", function (evt) {
                /// <summary>恢复编辑模式时重置插件状态</summary>
                if (evt.editor.mode == 'wysiwyg' && formattag.enable) {
                    pluginCmd.exec();
                }
            });

            //editor.on('instanceReady', function () {
            //    /// <summary>修正撤销功能的镜像</summary>
            //    var undoImagePrototype = CKEDITOR.plugins.undo.Image.prototype;
            //    undoImagePrototype.equals = CKEDITOR.tools.override(undoImagePrototype.equals, function (org) {
            //        return function (otherImage) {
            //            var thisContents = this.contents, otherContents = otherImage.contents;

            //            if (formattag.enable) {
            //                this.contents = formattag.clearFormatTag(thisContents) || '';
            //                otherImage.contents = formattag.clearFormatTag(otherContents) || '';
            //            }
            //            var retval = org.apply(this, arguments);

            //            this.contents = thisContents;
            //            otherImage.contents = otherContents;
            //            return retval;
            //        };
            //    });
            //});

            editor.on('afterCommandExec', function (ev) {
                /// <summary>当执行撤销或重做时刷新回车符显示状态</summary>
                if (!formattag.enable)
                    return;
                if (editor.mode == 'wysiwyg' && (ev.data.name == 'undo' || ev.data.name == 'redo'))
                    window.setTimeout(function () { formattag.reset(editor); }, 10);
            });

            editor.on("contentDom", function () {
                var doc = editor.document.$;
                if (CKEDITOR.env.ie) {
                    editor.document.$.execCommand('RespectVisibilityInDesign', true, true);
                }
                editor.document.on('keydown', function (evt) {
                    if (!formattag.enable) {
                        return;
                    }
                    formattag.repeat = evt.data.$.repeat;
                });
                //检查回车符
                editor.document.on('keyup', function (evt) {
                    if (!formattag.enable) {
                        return;
                    }
                    var keyCode = evt.data.getKey();
                    formattag.console.log("keycode:" + keyCode);
                    if (keyCode > 32 && keyCode < 45) {
                        editor.document.fire('cursorChange', evt.data.$);
                        return;
                    }
                    //editor.fire('lockSnapshot');
                    var sel = editor.getSelection();
                    var orgRange = sel.getRanges()[0];
                    var range = orgRange.clone();
                    var selNode = range.startContainer;

                    if (keyCode == 32) {//Spacebar
                        return;
                        var content;
                        //debugger;
                        var bookmark = range && range.createBookmark(true);
                        if (selNode.type == CKEDITOR.NODE_TEXT) {
                            content = selNode.getText();
                            content = content.replace(/&#160;|&nbsp;| /ig, "<span class=\"plugin_formattag_space\" data-formattag=\"space\">&nbsp;</span>");

                        }
                        if (selNode.type == CKEDITOR.NODE_ELEMENT) {
                            content = selNode.getHtml();
                            content = formattag.setFormatTag(content, true);
                        }
                        var frame = new CKEDITOR.dom.element('span');
                        frame.setHtml(content);
                        var newText = CKEDITOR.dom.element.createFromHtml(content);
                        frame.replace(selNode);
                        //frame.remove(true);
                        if (range && bookmark) {
                            range.moveToBookmark(bookmark);
                        }
                        formattag.console.log(content);
                    }
                    if (keyCode == 13) { //Enter
                        if (formattag.repeat) {
                            formattag.reset(editor);
                            return;
                        }
                        var brNode = null, before = null;
                        if (selNode.type == CKEDITOR.NODE_ELEMENT) {
                            if (range.startOffset > 0 && !range.checkStartOfBlock()) {
                                //光标不起始位置不为0并且不在文本块的开始位置,查找前一个节点
                                before = selNode.getChild(range.startOffset - 1);
                            }
                        } else if (selNode.type == CKEDITOR.NODE_TEXT) {
                            //如果是文本节点，直接查找前一个节点
                            before = selNode.getPrevious();
                        }
                        while (before && before.type != CKEDITOR.NODE_ELEMENT) {
                            //查找前一个节点，直到找到的节点类型为element
                            before = before.getPrevious();
                        }
                        if (before && before.is && before.is("br")) {
                            brNode = before;
                            before = brNode.getPrevious();

                            while (before && before.type == CKEDITOR.NODE_TEXT && before.getText() == "") {
                                before = before.getPrevious();
                            }
                        }
                        if (brNode && !formattag.isBrNode(before)) {
                            range.setStartBefore(brNode);
                            range.collapse(true);
                            var flag = formattag.getBrNode(editor);
                            range.insertNode(flag);
                            
                        }
                        return;
                    }

                    if (
                        !((evt.data.$.ctrlKey && keyCode != 86) || evt.data.$.altKey) && //CTRL+v || ALT
                        ((keyCode >= 48 && keyCode <= 57) ||
                        (keyCode >= 65 && keyCode <= 90) ||
                        (keyCode >= 96 && keyCode <= 111 && keyCode != 108) ||
                        keyCode == 32 ||
                        (keyCode >= 186 && keyCode <= 192) ||
                        (keyCode >= 219 && keyCode <= 222) ||
                        (evt.data.$.ctrlKey && keyCode == 86))) {//CTRL+v
                        formattag.fixFlag(range);
                    }


                });
                editor.document.on('cursorChange', function (evt) {
                    /// <summary>当光标发生变化时修正光标的位置</summary>

                    if (!formattag.enable) {
                        return;
                    }
                    var sel = editor.getSelection();
                    if (!sel) {
                        return;
                    }

                    //找到el.data(formattag.name) == "on"的节点
                    var range = sel.getRanges()[0].clone();
                    if (range.collapsed) {
                        return;
                    }
                    //var book = range.createBookmark(true);
                    var selNode = range.startContainer;
                    var brNode, spaceNode, before, after;
                    //debugger;
                    if (selNode.type == CKEDITOR.NODE_ELEMENT) {
                        formattag.console.log("NODE_ELEMENT");
                        //range.select();
                        if (formattag.isSpaceNode(selNode)) {
                            spaceNode = selNode;
                        }
                        if (formattag.isBrNode(selNode)) {
                            brNode = selNode;
                        }
                        if (!range.checkStartOfBlock()) {
                            var before = selNode.getChild(range.startOffset - 1);
                            while (before && before.type == CKEDITOR.NODE_TEXT && before.getText() == "") {
                                before = before.getPrevious();
                            }
                        }
                        if (before && before.type == CKEDITOR.NODE_ELEMENT) {
                            if (formattag.isSpaceNode(before)) {
                                range.select();
                            }
                            if (formattag.isBrNode(before)) {
                                brNode = before;
                            }
                        }
                        if (!range.checkEndOfBlock()) {
                            after = selNode.getChild(range.startOffset);
                            while (after && after.type == CKEDITOR.NODE_TEXT && after.getText() == "") {
                                after = after.getNext();
                            }
                        }

                        if (after && after.type == CKEDITOR.NODE_ELEMENT && after.is('br')) {
                            //range.select();
                        }

                        if (before && before.type == CKEDITOR.NODE_ELEMENT && before.is('br')) {
                            //range.select();
                        }
                    } else {
                        formattag.console.log("text");
                        var parent = selNode.getParent();
                        if (parent && formattag.isBrNode(parent)) {
                            brNode = parent;
                        }
                        if (parent && formattag.isSpaceNode(parent)) {
                            spaceNode = parent;
                        }
                        range.select();
                    }

                    if (brNode) {
                        //已知问题，当每行内容为空的时候按左方向键移动光标的时候会返回到前面两行
                        if (evt.data.keyCode == 39) {
                            after = brNode.getNext();
                            if (after && after.is && after.is("br")) {
                                range.setEndAfter(after);
                                range.collapse(false);
                            }
                        } else {
                            range.setStartBefore(brNode);
                            range.collapse(true);
                        }
                        range.select();
                    }
                    if (spaceNode) {
                        //formattag.console.log("startOffset:" + range.startOffset);
                        if (range.startOffset == 0) {
                            range.setStartBefore(spaceNode);
                            range.collapse(true);
                        } else {
                            range.setEndAfter(spaceNode);
                            range.collapse(false);
                        }
                        range.select();
                    }
                });

                editor.document.on('mouseup', function (evt) {
                    /// <summary>检查控制影响光标定位的按键</summary>
                    formattag.console.log("mouseup");
                    if (!formattag.enable) {
                        return;
                    }
                    if (CKEDITOR.env.ie && 0 == 1) {
                        var selection = editor.document.$.selection;
                        var range = selection.createRange();
                        if (range.boundingWidth == 0 && range.boundingHeight > 0) {
                            //looks like its already at the start of the next line down...
                            //console.log('default position: ' + range.offsetLeft + ', ' + range.offsetTop);
                            //lets move the start of the range one character back
                            //(i.e. select the last char on the line)
                            range.moveStart("character", -1);
                            //now the range looks good (except that its width will be one char);
                            //console.log('one char back: ' + range.offsetLeft + ', ' + range.offsetTop);
                            //calculate the true end of the line...
                            //window.debug.appendHtml(range.boundingWidth + "<br/>");
                            if (range.boundingWidth == 0) {
                                range.collapse();
                                range.select();
                            } else {
                                var left = range.offsetLeft + range.boundingWidth;
                                var top = range.offsetTop;
                                //now we can collapse back down to 0 width range
                                range.collapse();
                                //the position looks right
                                //console.log('moving to: ' + left + ', ' + top);
                                //move there.
                                try {
                                    range.moveToPoint(left, top);
                                } catch (e) {
                                }
                            }
                        }
                    }
                    editor.document.fire('cursorChange', evt.data.$);
                }, null, null, 1);
            });
            CKEDITOR.addCss(
            '.' + formattag.brClassName +
                '{width:7px;overflow:hidden;display:inline-block;cursor:text;background:transparent url(' + this.path + 'images/br.gif' + ') no-repeat left center;}' +
                '.' + formattag.spaceClassName +
                '{background:green url(' + this.path + 'images/space.gif' + ') no-repeat left bottom;}'
            );
            var dataProcessor = editor.dataProcessor,
            htmlFilter = dataProcessor && dataProcessor.htmlFilter;
            htmlFilter && htmlFilter.addRules({
                elements: {
                    span: function (element) {
                        if (element.attributes['data-' + formattag.name]) {
                            delete element.name; // Write children, but don't write this node.
                            var rt = (element.attributes["class"] != formattag.brClassName && element) || false;
                            //debugger;
                            return rt;
                        }
                    }
                }
            });
        },
        afterInit: function (editor) {
            // 防止标记在清除格式时被删除
            var elementsPathFilters,
                    filter = function (element) {
                        if (element.data(formattag.name))
                            return false;
                    };

            if (editor._.elementsPath && (elementsPathFilters = editor._.elementsPath.filters))
                elementsPathFilters.push(filter);
            editor.addRemoveFormatFilter && editor.addRemoveFormatFilter(filter);
        }
    });
})();
